package day7.impl_pool;

import java.util.concurrent.*;
/**
 * 自己实现线程池
 */
public class MyThreadPoolExecutor implements Executor {

    // 核心线程最大数量
    private final int corePoolSize;
    // 最大线程数量
    private final int maxPoolSize;
    // 空闲时间
    private final long keepAliveTime;
    private final TimeUnit unit;
    // 任务队列
    private final BlockingQueue<Runnable> workQueue;
    // 线程工厂
    private final ThreadFactory threadFactory;

    // 当前核心线程数量
    private int curCorePoolSize;
    // 当前线程数量
    private int curPoolSize;

    // 构造方法
    public MyThreadPoolExecutor(int corePoolSize,
                                int maxPoolSize,
                                long keepAliveTime, TimeUnit unit,
                                BlockingQueue<Runnable> workQueue,
                                ThreadFactory threadFactory,
                                RejectedExecutionHandler handler) {
        this.corePoolSize = corePoolSize;
        this.maxPoolSize = maxPoolSize;
        this.keepAliveTime = keepAliveTime;
        this.unit = unit;
        this.workQueue = workQueue;
        this.threadFactory = threadFactory;
    }

    @Override
    public void execute(Runnable command) {
        // 1. 如果当前的核心线程数 < 最大核心线程数，就直接创建一个核心线程来执行任务
        if(curCorePoolSize < corePoolSize) {
            // 创建一个核心线程要做的工作
            Runnable job = new CoreJob(workQueue, command);
            // 创建核心线程，并分配任务
            Thread coreThread = threadFactory.newThread(job); // 通过线程工厂
            coreThread.setName("核心线程-" + curCorePoolSize);
            // 启动核心线程
            coreThread.start();
            // 核心线程一直在死循环中取任务，取不到任务就会进入阻塞状态。不会结束工作就不会被销毁。
            curCorePoolSize ++;
            curPoolSize ++;
        }else{
            // 2.将任务存放到任务队列中
            if(workQueue.offer(command)){
                // 这里用offer，不用put。因为我们需要立即得到结果(是否能放进去<=>是否需要临时线程)，而不是让主线程阻塞
                // 成功放入任务队列中
            }else {
                // 3.队列已满，创造临时线程执行任务
                if(curPoolSize < maxPoolSize){
                    Runnable job = new TemporaryJob(keepAliveTime, unit, workQueue, command);
                    Thread tmpThread = threadFactory.newThread(job);
                    tmpThread.setName("临时线程-" + (curPoolSize - corePoolSize));
                    tmpThread.start();
                    // 临时线程取不到任务就会break跳出循环结束，工作结束后会被自动销毁
                    curPoolSize ++;
                }else{
                    // 4. 已经达到最大线程数，此时采用拒绝策略
                    throw new RejectedExecutionException();
                }
            }
        }
    }
}
